# backup.py 
# backup.py : the function is : in a period of time, once the supervised folder changed,\
#             it can backup and compress the changed file to the directory the user set in advance.\
#             send mail to the user,notify te changes in the files,and create log file to recording the \
#             changes in the file.
#
#
# Copyright from 2012 - 2015
# 
# 1Sep 2012 - Create by Wang Huanhuan

import time
import os
from   os.path import join
import shutil
import datetime
import sys
import logging
import zipfile
import smtplib
from   sendmail import SendMail

class Backup:
    def __init__(self,src_Files,des,from_mail,psw,to_mail):        
        if not os.path.isdir(des):
            os.makedirs(des)
            
        self.FileNoChange  = []                    # To be store the no changed file 
        self.FileChange    = []                    # To be store changed files 
        self.FileCreate    = []                    # To be store the new create files
        self.FileDel       = []                    # To be store the deleted files
        self.new_Files     = []                    # To be store new files list,after remove the same filename,pass the rest to the FileDel.
        self.Files_slp     = []                    # To be store for the files list after the programe sleep for a while,\
                                                   # After remove the same filename,pass the rest to FileCreate.
        self.src_Files     = src_Files             # To be store the files which passed by the user.
        self.des           = des                   # Base path of destination
        self.from_mail     = from_mail             # The send mail address
        self.psw           = psw                   # The pass word of the from mail
        self.to_mail       = to_mail               # The recessive mail address
        self.timeoutStyle  = ['sleep','duration']      # Timout: sleep - sleep timeout; duration - working time style
        self.sleepTimeout  = 10                        # Default sleep timeout is 10s. See also: setTimeout
        self.workingTime   = 60                        # Default working time is 1 min. See also: setTimeout
        self.starttime     = datetime.datetime.now()   # Get start time of the process

    def creatlog(self):
        ''' Log file generated record debugging information.
        '''
        logger  = logging.getLogger()                          # Instantiated logger
        handler = logging.FileHandler( self.des + 'Log.txt')   # Call logger , used to disseminate information
        logger.setLevel(logging.NOTSET)                        # Set the level
        logger.addHandler(handler)                             # Through addHandler add  handle

        if len(self.FileChange) > 0:
            for file_change in self.FileChange:
                change_detail = "%s changed,re-copy at the time of %s" %(file_change,time.strftime('%Y%m%d%H%M%S'))
        else:
            change_detail = "No file changed!"
        logger.debug(change_detail)                            # Output debug information

        if len(self.FileCreate) > 0:
            for file_create in self.FileCreate:
                create_detail = "%s is new created." %file_create
        else:
            create_detail = "No file is new create!" 
        logger.debug(create_detail)

        if len(self.FileDel) > 0:
            for file_del in self.FileDel:
                del_detail = "%s is deleted." %file_del
        else:
            del_detail = "No file deleted!"
        logger.debug(del_detail)

        self.FileChange = []
        self.FileCreate = []
        self.FileDel    = []
        
        detail    = [change_detail,create_detail,del_detail]
        self.mail_info = '\r\n'.join(detail)
        sm  = SendMail(self.from_mail, self.psw, self.to_mail,self.mail_info)
        sm.send_mail()
        print 'Successful record debug information in log file!'

    def zip_file(self,filesname):
        ''' zip_file : Compress multiple files or single file, 
                       and store the compressed file folder named for the time .
            <filesname> - Array used to store files.
        '''
        target = self.des + time.strftime('%Y%m%d%H%M%S')                                     
        if not os.path.isdir(target):
            os.makedirs(target)
        zip_filename = target + '\\' + time.strftime('%Y%m%d%H%M%S') + '.zip'   # Create folder for store the compressed file 
        zfile        = zipfile.ZipFile( zip_filename, 'w', zipfile.ZIP_DEFLATED)   
        for file in filesname:
            zfile.write(file)
        zfile.close()

    def _backup(self):
        ''' _backup: public function
            Within a certain time , when the file changes ,
            the program will perform the copy operation.
        '''
        for fileObj in self.src_Files:
            if os.path.isfile(fileObj) == True:
                self.new_Files.append(fileObj)
            else:
                for root, dirs, files in os.walk(fileObj):
                    for filename in files:
                        self.new_Files.append(os.path.join(root, filename))
        print "There are %d files waiting to be examined whether changes,pls. \nwait a moment..." %len(self.new_Files)
        
        mod_time = {}                               # Create an empty dictionary,Where key is filename,value is file's modify time
        for fileObject in self.new_Files:
            if os.path.isfile(fileObject) == True:
                file_mtime           = time.ctime(os.stat(fileObject).st_mtime)
                mod_time[fileObject] = file_mtime   # First: get modify time of object 
                                                    # ctime--A time stamp ( default converted into a time string for the current time)
                                                    # st_mtime--Get time of last modification
                                                    # os.stat--Get the status of files               
            else:
                print '%s does not exist!' % fileObject
            
        time.sleep(self.sleepTimeout)               # Sleep time for checking modification time
        print "The programe stop %d sec" % self.sleepTimeout
        
        for fileObj in self.src_Files:
            if os.path.isfile(fileObj) == True:
                self.Files_slp.append(fileObj)
            else:
                for root, dirs, files in os.walk(fileObj):
                    for filename in files:
                        self.Files_slp.append(os.path.join(root, filename))
        mod_time_slp = {}                           # Aftre the programe sleep time,create an empty dictionary,\
                                                    # where key is filename,value is file's modify time
        for fileObject in self.Files_slp:
            if os.path.isfile(fileObject) == True:
                file_mtime_slp = time.ctime(os.stat(fileObject).st_mtime)   # Second: get modify time of object after the sleep time
                mod_time_slp[fileObject]  = file_mtime_slp   
            else :
               print '%s does not exist!' % fileObject
            
        for fname_new in self.new_Files:             # Compare the filename in new_Files and self.Files_slp,\
                                                     # find out which file changed,deleted or new created
            for fname_slp in self.Files_slp:
                if fname_new == fname_slp:
                    self.FileNoChange.append(fname_new)

        for filename in self.FileNoChange:
            self.new_Files.remove(filename)
            self.Files_slp.remove(filename)
        self.FileDel    = self.new_Files
        self.FileCreate = self.Files_slp
                           
        for filename in self.FileNoChange:          # If the filename is the same,to check the modify time
            if mod_time_slp[filename] != mod_time[filename] :                                                                 
                try: 
                    self.FileChange.append(filename)
                    print ' %s changed,it will be compressed!' %filename
                except:
                    print "backup failed :  exit."
                    sys.exit()                      # Exit the working
            else:
                print 'The file:%s does not change, will not be compressed!' % filename
        if len(self.FileChange) > 0:  
            self.zip_file(self.FileChange)
            print "The changed files %s are successfully compressed ! " %self.FileChange
        
        self.FileNoChange = []                     
        self.new_Files    = []                         
        self.Files_slp    = [] 
    
    def setTimeout(self,timeout,style):
        ''' setTimeout :
            <timeout> - Timeout to be set as $style,defalut is seconds
            <style>   - The sytle of timeout,it contains sleep style and duration (working time) style
                        See alse : self.timeoutStyle
        '''
        if not style in self.timeoutStyle:
            print "%s is not in %s, pls double check it." % (style,self.timeoutStyle)
            return False
            
        if not str(timeout).isdigit():
            print "Timeout set failed caused by wrong style of %s" % timeout
            return False
        
        if style is self.timeoutStyle[0]:
            self.sleepTimeout = timeout   # Set sleeping time
        else:
            self.workingTime  = timeout   # Set working time
            return True
         
    def startBackup(self):
        ''' startBackup:
            start backup function
        '''
        while True:
            nowTime = datetime.datetime.now()
            if (nowTime - self.starttime).seconds >= self.workingTime:
                break
            self._backup()
            self.creatlog()

if __name__ == "__main__":
    file       = 'E:\\1'
    sou_file   = [file]
    target_dir = 'F:\\backup\\'  
    from_mail  = "whuan0224@126.com"
    psw        = "13808227437whh"
    to_mail    = "401329705@qq.com"

    backObj = Backup(sou_file,target_dir,from_mail,psw,to_mail)
    backObj.setTimeout(10,'sleep')
    backObj.setTimeout(300,'duration')
    backObj.startBackup()
    
